import { _decorator, color, Color, Component, Graphics, instantiate, Label, Node, Prefab, tween, UIOpacity, v3, Vec3 } from 'cc';
import { GameData } from '../Data/GameData';
import { UserData } from '../Data/UserData';
import Tools from '../Tools/Tools';
import PoolMgr from './PoolMgr';
import { UIMgr } from './UIMgr';
import { AudioMgr } from './AudioMgr';
import { Url } from '../Tools/Url';
import { GameMgr } from './GameMgr';
const { ccclass, property } = _decorator;

@ccclass('BoardMgr')
export class BoardMgr extends Component {

    /** 单例模式 */
    private static _ins: BoardMgr;

    constructor() {
        super();
        BoardMgr._ins = this;
    }
    public static get ins(): BoardMgr {
        if (!BoardMgr._ins) {
            BoardMgr._ins = new BoardMgr();
        }
        return BoardMgr._ins;
    }
    @property(Prefab)
    wordPre: Prefab = null;
    /** 绘图节点组件 */
    @property(Graphics)
    private graphicsComs: Graphics[] = [];
    /** 答案显示容器 */
    @property(Node)
    private answerContainer: Node = null;
    /** cond提示字母字符串 */
    private condwordStr: string = '';
    /** 单词地图容器 */
    @property(Node)
    private boardContainer: Node = null;
    /** 棋盘大小 */
    private boardWidth: number = 900;
    private boardHeight: number = 900;
    /** 所有正确答案的单词 */
    public correctAnswerText: string[] = [];
    /** 所有的正确答案下标 */
    public correctAnswerIndexes: number[][][] = [];
    /** 所有数据对应颜色 */
    public correctcolorFormIndex: string[][] = [];
    /** 棋盘对应的word节点 */
    public wordNodeArr: Node[][] = [];
    /** 棋盘节点对应的触摸锁 */
    public wordNodeLockArr: boolean[][] = [];
    /** 棋盘对应的wordStr */
    public wordStrArr: string[][] = [];
    /** 当前关卡连线次数 */
    public drawLineTimes: number = 0;

    /** 引导关卡的固定配置-单词/单词顺序 *///3      4      1      2
    private level1Words: string[] = ['DOG', 'AIR', 'SUN', 'ICE'];
    private level1Reverse: boolean[] = [true, false, false, true];
    public level1WordsIndex: number = 0; // 计数器，用于记录获取到第几个元素
    public level1ReverseIndex: number = 0; // 计数器，用于记录获取到第几个元素

    length3Pos: Vec3[] = [v3(-320, 0, 0), v3(0, 0, 0), v3(320, 0, 0)];
    length7Pos: Vec3[] = [v3(-320, 75, 0), v3(0, 75, 0), v3(320, 75, 0), v3(0, 0, 0), v3(-320, 0, 0), v3(320, 0, 0), v3(0, -75, 0)];
    lengthmorePos: Vec3[] = [v3(-320.5, 50, 0), v3(0, 50, 0), v3(320.5, 50, 0), v3(0, -50, 0), v3(-320.5, -50, 0), v3(320.5, -50, 0)];

    public wordColorStr: string = '#FFFFFF';
    public currentGraphicsIndex: number = 7; // 初始化索引

    public showOneAnswerFristWordTimes: number = 0;

    private board_render_token: string;

    private render_record: {
        token: string,
        board_data: any[][]
    } = {} as any;
    /** 根据关卡初始化棋盘数据 */
    gameBoardInit() {
        mtec.delay(0.5, ()=>this.recheckTheChessboard());
        let token = mtec.string.randomToken(3, 36, t => t != this.board_render_token);
        this.board_render_token = token;

        let isReversed = (Math.random() < 0.5) || (UserData.data.curLevel == 0);
        this.render_record.token = token;

        let data_list: typeof GameData.data.boardData[`type${1 | 2 | 3 | 4 | 5}Data`];
        if (UserData.data.curLevel <= 7) {
            data_list = GameData.data.boardData.type1Data;
        } else if (UserData.data.curLevel >= 8 && UserData.data.curLevel <= 13) {
            data_list = GameData.data.boardData.type2Data;
        } else if (UserData.data.curLevel >= 14 && UserData.data.curLevel <= 24) {
            data_list = GameData.data.boardData.type3Data;
        } else if (UserData.data.curLevel >= 25 && UserData.data.curLevel <= 55) {
            data_list = GameData.data.boardData.type4Data;
        } else if (UserData.data.curLevel >= 56) {
            data_list = GameData.data.boardData.type5Data;
        }

        // let levelConfig = Tools.arrayRand(GameData.data.boardData[data_name]);
        let levelConfig = data_list[UserData.data.curLevel == 0 ? 0 : Math.floor(Math.random() * data_list.length)];
        let board_data = isReversed ? levelConfig : Tools.rotateMatrix(levelConfig, Math.random() < 0.5);
        this.render_record.board_data = board_data;
        // console.log('BoardDataInfo===', UserData.data.curLevel, '\nlevelConfig: ' + JSON.stringify(levelConfig), '\nconfig: ' + JSON.stringify(board_data));
        this.generateWordBoard(token, board_data);
        this.genearColorBoard(token, board_data);
        this.updateAnswerWord(token);
    }
    // console.log('棋盘配置；', GameData.data.boardData.type1Data[0]);
    // console.log('字母节点：', this.wordNodeArr);
    // console.log('棋盘节点触摸锁', this.wordNodeLockArr);
    // console.log('字母字符', this.wordStrArr);
    // console.log('正确答案下标数组；', this.correctAnswerIndexes);
    // console.log('正确答案文本：', this.correctAnswerText);
    // console.log('字母对应的颜色：', this.correctcolorFormIndex);

    /** 清空棋盘字母节点 */
    public clearBoardWord() {
        this.boardContainer.destroyAllChildren();
    }
    /** 清空棋盘颜色 */
    public clearBoardLineColor() {
        for (let i = 0; i < this.graphicsComs.length; i++) {
            this.graphicsComs[i].clear();
        }
    }

    private render_answer_token: string
    /** 更新单词答案区域 */
    public updateAnswerWord(token: string) {

        if (this.correctAnswerText.length <= 3) {
            for (let i = 0; i < this.correctAnswerText.length; i++) {
                const element = this.answerContainer.children[i];
                element.setPosition(this.length3Pos[i])
            }
        } else if (this.correctAnswerText.length > 3 && this.correctAnswerText.length <= 6) {
            for (let i = 0; i < this.correctAnswerText.length; i++) {
                const element = this.answerContainer.children[i];
                element.setPosition(this.lengthmorePos[i])
            }
        } else {
            for (let i = 0; i < this.correctAnswerText.length; i++) {
                const element = this.answerContainer.children[i];
                element.setPosition(this.length7Pos[i])
            }
        }

        let count = 0;
        for (let i = 0; i < this.answerContainer.children.length; i++) {
            const element = this.answerContainer.children[i];
            if (this.correctAnswerText[i]) {
                count++;
                element.getComponent(UIOpacity).opacity = 255;
                element.getComponent(Label).string = this.correctAnswerText[i];
            } else {
                element.getComponent(UIOpacity).opacity = 0;
            }
        }
        // console.log('updateAnswerWord,correctAnswerText', JSON.stringify(this.correctAnswerText));
        if (count > 0) {
            this.render_answer_token = token;
        }
    }

    /** 重新检查棋盘和答案区是否更新 */
    recheckTheChessboard() {
        if (this.render_color_token !== this.render_record.token) {
            console.log('genearColorBoard ERROR：', JSON.stringify(this.render_record.board_data));
            this.genearColorBoard(this.render_record.token, this.render_record.board_data)
        } else if (this.render_words_token !== this.render_record.token) {
            console.log('generateWordBoard ERROR：', JSON.stringify(this.render_record.board_data));
            this.generateWordBoard(this.render_record.token, this.render_record.board_data);
        } else if (this.render_answer_token !== this.render_record.token) {
            console.log('updateAnswerWord ERROR：', JSON.stringify(this.correctAnswerText));
            this.updateAnswerWord(this.render_record.token);
        }
    }

    public render_color_token: string
    /** 根据配置生成棋盘颜色配置 */
    private genearColorBoard(token: string, _boardConfig: number[][]) {
        Tools.shuffle1(GameData.colorHEX);
        // console.log(GameData.colorHEX);

        const colorMap: { [key: number]: string } = {}; // 存储每个数值对应的颜色
        let colorIndex = 0; // 定义一个索引变量，用于按顺序取颜色

        // 初始化 correctcolorFormIndex 的大小
        this.correctcolorFormIndex = Array(_boardConfig.length).fill(null).map(() => Array(_boardConfig[0].length).fill(''));

        // 遍历棋盘配置，找到相同数值的下标
        for (let row = 0; row < _boardConfig.length; row++) {
            for (let col = 0; col < _boardConfig[row].length; col++) {
                const value = _boardConfig[row][col];

                // 如果当前数值还没有对应的颜色，从 GameData.colorHEX 里按顺序取一个颜色
                if (!colorMap[value]) {
                    colorMap[value] = GameData.colorHEX[colorIndex];
                    colorIndex = (colorIndex + 1) % GameData.colorHEX.length; // 确保颜色索引不会超出数组长度
                }

                // 将颜色赋值给 correctcolorFormIndex 对应的下标
                this.correctcolorFormIndex[row][col] = colorMap[value];
            }
        }

        this.render_color_token = token;
    }

    public render_words_token: string
    /** 生成单词棋盘地图 */
    generateWordBoard(token: string, _boardConfig: number[][]) {
        // console.log('enterGenerateWordBoard');

        const rows = _boardConfig.length;
        const cols = _boardConfig[0].length;

        this.wordNodeArr = [];  // 初始化wordNodeArr二维数组
        this.wordNodeLockArr = [] //    初始节点触摸锁
        this.wordStrArr = [];   // 初始化单词文本数组
        this.correctAnswerIndexes = [];  // 初始化存储正确答案下标数组的数组
        this.correctAnswerText = [];    // 初始化存储正确答案单词文本的数组
        // 计算每个单词块的宽高
        const wordWidth = this.boardWidth / cols;
        const wordHeight = this.boardHeight / rows;

        for (let i = 0; i < rows; i++) {
            this.wordNodeArr[i] = [];  // 初始化行
            this.wordNodeLockArr[i] = [];
            this.wordStrArr[i] = [];
            for (let j = 0; j < cols; j++) {
                // 创建单词块
                let word = instantiate(this.wordPre);
                //let word = await PoolMgr.getObject('word');
                this.boardContainer.addChild(word);
                this.wordNodeArr[i][j] = word;  // 将word存入wordNodeArr二维数组
                this.wordNodeLockArr[i][j] = true;
                word.getComponent(UIOpacity).opacity = 0;
                word.setScale(1, 1, 1)
                // 设置单词块的大小
                // word.getComponent(UITransform).width = wordWidth;
                // word.getComponent(UITransform).height = wordHeight;

                // 计算单词块的位置
                const x = (j * wordWidth) + (wordWidth / 2) - (this.boardWidth / 2);
                const y = ((rows - 1 - i) * wordHeight) + (wordHeight / 2) - (this.boardHeight / 2);
                word.setPosition(x, y);


            }
        }

        // 填充字母到wordNodeArr中的单词块
        const wordMap = this.generateWordMap(_boardConfig);
        for (let value in wordMap) {
            const positions = wordMap[value];
            const wordLength = positions.length;
            let word: string
            if (UserData.data.curLevel == 0) {
                // 使用计数器从数组中获取元素，且不改变数组
                if (this.level1WordsIndex < this.level1Words.length) {
                    word = this.level1Words[this.level1WordsIndex];
                    this.level1WordsIndex++; // 更新索引
                } else {
                    console.warn("level1Words 数组中的单词已用完");
                }
            } else {
                word = this.getWordFromDictionary(wordLength);
            }

            this.correctAnswerText.push(word);
            // 40%几率反向填入字母
            let isReversed: boolean;
            if (UserData.data.curLevel == 0) {
                // 使用计数器从数组中获取元素，且不改变数组
                if (this.level1ReverseIndex < this.level1Reverse.length) {
                    isReversed = this.level1Reverse[this.level1ReverseIndex];
                    this.level1ReverseIndex++; // 更新索引
                } else {
                    console.warn("level1Reverse 数组中的元素已用完");
                }
            } else {
                isReversed = Math.random() < 0.3;
            }
            const correctIndexes = [];


            for (let k = 0; k < wordLength; k++) {
                const idx = isReversed ? wordLength - 1 - k : k;
                const [i, j] = positions[k];
                const wordnode = this.wordNodeArr[i][j]
                const wordLabel = wordnode.getChildByName('lbl_word')?.getComponent(Label);
                if (wordLabel) {
                    wordLabel.string = word[idx];
                    this.wordStrArr[i][j] = word[idx];
                }
                wordnode.getComponent(UIOpacity).opacity = 255;
                correctIndexes.push([i, j]);
            }

            // 如果是反向填入，需要将correctIndexes反转后保存
            this.correctAnswerIndexes.push(isReversed ? correctIndexes.reverse() : correctIndexes);
        }


        for (let i = 0; i < rows; i++) {
            for (let j = 0; j < cols; j++) {
                // 如果当前数据为0，填充随机字母
                if (_boardConfig[i][j] === 0) {
                    const wordnode = this.wordNodeArr[i][j];
                    const wordLabel = wordnode.getChildByName('lbl_word')?.getComponent(Label);
                    if (wordLabel) {
                        let w = this.getRandomLetter(i, j);
                        wordLabel.string = w;
                        this.wordStrArr[i][j] = w;
                        wordnode.getComponent(UIOpacity).opacity = 255;
                        this.wordStrArr[i][j]
                    }
                }
            }
        }

        this.render_words_token = token;
    }
    /** 生成一个字母映射 */
    private generateWordMap(_boardConfig: number[][]): { [key: number]: [number, number][] } {
        const wordMap: { [key: number]: [number, number][] } = {};

        for (let i = 0; i < _boardConfig.length; i++) {
            for (let j = 0; j < _boardConfig[i].length; j++) {
                const value = _boardConfig[i][j];
                if (value !== 0) {
                    if (!wordMap[value]) {
                        wordMap[value] = [];
                    }
                    wordMap[value].push([i, j]);
                }
            }
        }

        return wordMap;
    }
    /** 根据单词长度从字典获取单词 */
    private getWordFromDictionary(length: number): string {

        switch (length) {
            case 3:
                return this.getRandomWord(GameData.data.word3Json);
            case 4:
                return this.getRandomWord(GameData.data.word4Json);
            case 5:
                return this.getRandomWord(GameData.data.word5Json);
            case 6:
                return this.getRandomWord(GameData.data.word6Json);
            default:
                return '';
        }
    }
    /** 从字典中随机获取单词 */
    private getRandomWord(dictionary: { ID: string; content: string }[]): string {


        let randomWord = '';

        const isValidWord = (word: string): boolean => {
            // 检查单词是否与 this.correctAnswerText 中的单词部分重合
            for (let existingWord of this.correctAnswerText) {
                if (this.isPartiallyOverlapping(existingWord, word)) {
                    return false; // 如果存在部分重合，返回false
                }
            }

            // 检查单词格式是否为ABA，ABCBA，ABCDCBA
            const len = word.length;
            for (let i = 0; i < Math.floor(len / 2); i++) {
                if (word[i] !== word[len - 1 - i]) {
                    return true; // 格式不为ABA、ABCBA、ABCDCBA，返回true
                }
            }
            return false; // 格式为ABA、ABCBA或ABCDCBA，返回false
        };

        // 随机获取单词并确保它有效
        do {
            const randomIndex = Math.floor(Math.random() * dictionary.length);
            randomWord = dictionary[randomIndex].content;
        } while (!isValidWord(randomWord));

        return randomWord;
    }

    /** 判断两个单词是否部分重合 */
    private isPartiallyOverlapping(word1: string, word2: string): boolean {
        const len1 = word1.length;
        const len2 = word2.length;

        for (let i = 0; i < len1; i++) {
            for (let j = 0; j < len2; j++) {
                let k = 0;
                while (i + k < len1 && j + k < len2 && word1[i + k] === word2[j + k]) {
                    k++;
                    if (k >= 3) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /** 随机获取一个英文字母 */
    private getRandomLetter(i: number, j: number): string {
        const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
        let excludedLetters = new Set<string>();

        // 排除所有答案的首字母和尾字母
        for (let word of this.correctAnswerText) {
            if (word.length > 0) {
                excludedLetters.add(word[0]); // 首字母
                excludedLetters.add(word[word.length - 1]); // 尾字母
            }
        }

        // 过滤掉被排除的字母
        let availableLetters = letters.split('').filter(letter => !excludedLetters.has(letter));

        // 如果过滤后没有可用字母，保底使用整个字母表
        if (availableLetters.length === 0) {
            console.warn('所有字母都被排除，重置为完整字母表');
            availableLetters = letters.split('');
        }

        // 随机选择可用的字母
        const randomIndex = Math.floor(Math.random() * availableLetters.length);
        const randomLetter = availableLetters[randomIndex];

        return randomLetter;
    }

    /** 显示所有答案单词的首字母 */
    public showAllAnswerFristWord() {
        AudioMgr.ins.playOneShot(Url.AUDIO.SFX8, 1);
        GameMgr.ins.isUseProp = true;
        this.correctAnswerIndexes.forEach(([firstIndex], index) => {
            const [row, col] = firstIndex as unknown as [number, number];
            const wordNode = this.wordNodeArr[row][col];
            tween(this.wordNodeArr[row][col])
                .to(0.3, { scale: v3(1.2, 1.2, 1.2) })
                .to(0.3, { scale: v3(1, 1, 1) })
                .start()
            if (wordNode) {
                // 放大节点10%
                const currentScale = wordNode.scale;
                wordNode.setScale(currentScale.x * 1.1, currentScale.y * 1.1);

                // 获取节点的位置并在其位置画一个黑色的圆
                const pos = wordNode.getPosition();
                // console.log(index);

                this.graphicsComs[7 + index].circle(pos.x, pos.y, 55);
                this.graphicsComs[7 + index].fillColor = new Color().fromHEX(this.correctcolorFormIndex[row][col]);
                this.graphicsComs[7 + index].fill();
            }
        });
    }
    /** 显示第一个答案单词的首字母 */
    public showOneAnswerFristWord() {
        while (this.showOneAnswerFristWordTimes < this.correctAnswerIndexes.length) {
            const [firstIndex] = this.correctAnswerIndexes[this.showOneAnswerFristWordTimes];
            const [row, col] = firstIndex as unknown as [number, number];

            // 如果当前位置未锁定，继续寻找下一个
            if (!this.wordNodeLockArr[row][col]) {
                this.showOneAnswerFristWordTimes++;
                continue;
            }

            // 放大和绘制首字母效果
            tween(this.wordNodeArr[row][col])
                .to(0.3, { scale: v3(1.2, 1.2, 1.2) })
                .to(0.3, { scale: v3(1, 1, 1) })
                .start();

            AudioMgr.ins.playOneShot(Url.AUDIO.SFX8, 1);
            const wordNode = this.wordNodeArr[row][col];

            if (wordNode) {
                const currentScale = wordNode.scale;
                wordNode.setScale(currentScale.x * 1.1, currentScale.y * 1.1);
                const pos = wordNode.getPosition();

                this.graphicsComs[this.currentGraphicsIndex].circle(pos.x, pos.y, 55);
                this.graphicsComs[this.currentGraphicsIndex].fillColor = new Color().fromHEX(this.correctcolorFormIndex[row][col]);
                this.graphicsComs[this.currentGraphicsIndex].fill();

                this.currentGraphicsIndex++;
                this.showOneAnswerFristWordTimes++;
            }
            break; // 找到并处理第一个单词的首字母后退出循环
        }
    }

    /** 选择的单词显示在cond容器 */
    public showCondWord(selectedIndexes: number[][], color) {
        this.condwordStr = '';
        for (let i = 0; i < selectedIndexes.length; i++) {
            const index = selectedIndexes[i];
            this.condwordStr += this.wordStrArr[index[0]][index[1]];
        }
        UIMgr.ins.updateCondLabel(this.condwordStr, color);
    }
    /** 选择的单词进行连线 */
    public drawLineToWord(selectedIndexes: number[][]) {
        let index = selectedIndexes[0];
        if (!index) {
            return
        }
        //  清除上一次连线
        this.graphicsComs[this.drawLineTimes].clear();
        this.graphicsComs[this.drawLineTimes].strokeColor = new Color().fromHEX(this.correctcolorFormIndex[index[0]][index[1]]);
        this.graphicsComs[this.drawLineTimes].lineWidth = 110;
        //  重新绘制线
        for (let i = 0; i < selectedIndexes.length - 1; i++) {
            let pos1 = this.wordNodeArr[selectedIndexes[i][0]][selectedIndexes[i][1]].position;
            let pos2 = this.wordNodeArr[selectedIndexes[i + 1][0]][selectedIndexes[i + 1][1]].position;
            this.graphicsComs[this.drawLineTimes].moveTo(pos1.x, pos1.y);
            this.graphicsComs[this.drawLineTimes].lineTo(pos2.x, pos2.y);
            this.graphicsComs[this.drawLineTimes].stroke();
        }
    }
    /** 清除连线和还原word节点大小 */
    public clearLineAndAndReduction(touchNodeArr: Node[], drawTimes: number) {
        for (let i = 0; i < touchNodeArr.length; i++) {
            touchNodeArr[i].setScale(1, 1)
        }
        this.graphicsComs[this.drawLineTimes].clear();
    }
    /** 选中的字母先画一个圆 */
    public drawCircleToWord(touState: 'Start' | 'End', selectedIndexes: number[][]) {
        let index = selectedIndexes[0];
        if (!index) {
            return
        }
        let node = this.wordNodeArr[index[0]][index[1]]
        if (touState == 'Start') {
            // 放大节点10%
            node.setScale(1.1, 1.1);

            // 获取节点的位置并在其位置画一个黑色的圆
            const pos = node.getPosition();
            this.graphicsComs[14].circle(pos.x, pos.y, 55);
            this.wordColorStr = this.correctcolorFormIndex[index[0]][index[1]]
            this.graphicsComs[14].fillColor = new Color().fromHEX(this.wordColorStr);
            this.graphicsComs[14].fill();
        } else {
            node.setScale(1, 1);
            this.graphicsComs[14].clear();
        }

    }

    /** 根据 wordNodeLockArr 中的值，设置对应 wordNodeArr 中 Label 的颜色：false 为黑色，true 为白色 */
    public applyColorToNodesBasedOnLockStatus() {
        // 遍历 wordNodeLockArr 数组
        for (let i = 0; i < this.wordNodeLockArr.length; i++) {
            for (let j = 0; j < this.wordNodeLockArr[i].length; j++) {
                // 获取对应的 wordNodeArr 中的节点
                const node = this.wordNodeArr[i][j];
                if (node) {
                    // 获取节点的 'lbl_word' 子节点的 Label 组件
                    const label = node.getChildByName('lbl_word')?.getComponent(Label);
                    if (label) {
                        if (this.wordNodeLockArr[i][j] === false) {
                            // 如果当前节点未被锁定 (即值为 false)，设置颜色为白色
                            label.color = Color.WHITE;
                        } else if (this.wordNodeLockArr[i][j] === true) {
                            // 如果当前节点已被锁定 (即值为 true)，设置颜色为黑色
                            label.color = Color.BLACK;
                        }
                    }
                }
            }
        }
    }



}
